/****************************************************
 * 
 * home soft 版权所有.
 * 
 *****************************************************/

package com.homesoft.runtime.serialization;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.homesoft.runtime.dataobject.entity.IEntity;
import com.homesoft.runtime.dataobject.ienum.IEnum;

/**
 * @author lihg
 * @data   2012-9-13
 */
public abstract class BaseSerializer {
	private Map<String, Object> _map;
	 protected BaseSerializer()
     {
         this._map = new HashMap<String, Object>();
     }
	 public Object ConvertToObject(Object targetObj)
     {
         Object resultObj = null;
         if (targetObj == null)
         {
             return null;
         }
         if (targetObj instanceof IEntity)
         { // 实体类型
             resultObj = this.ConvertEntityToObject((IEntity)targetObj);
         }
         else if (targetObj instanceof IEnum)
         {
             resultObj = this.ConvertEnumToObject((IEnum)targetObj);
         }
         else
         { // 非实体类型
             if (List.class.isAssignableFrom(targetObj.getClass()))
             { // 集合类型
                 resultObj = this.CollectionToObject((List)targetObj);
             }else if(targetObj.getClass().isArray()){
            	  resultObj = this.CollectionToObject(targetObj);
             }
             else
             { // 非集合类型
                 Class objType = targetObj.getClass();
                 if (typeof(IConvertible).IsAssignableFrom(objType))
                 { // 内置类型
                     resultObj = this.NativeObjectToObject(targetObj);
                 }
                 else
                 { // 非集合引用类型,纯POJO转换
                     resultObj = this.PocoObjectToObject(targetObj);
                 }
             }
         }
         return resultObj;
     }
     public Object ConvertEnumToObject(IEnum iEnum)
     {
         IDictionary<string, Object> map = this._map;
         string hashCode = iEnum.GetHashCode().ToString();
         Object resultObj = this.ResultObject;
         bool contain = map.ContainsKey(hashCode);
         if (contain)
         {// 已经序列化过了
             this.AddRefObject(resultObj, hashCode);
             return resultObj;
         }
         else
         {
             map.Add(hashCode, iEnum);
         }
         this.AddHashField(resultObj, hashCode);
         string typeName = iEnum.TypeName;
         this.AddTypeField(resultObj, typeName);

         return this.GTPEnumToObject(iEnum);// GTPEnumToObject(iEnum, itemInfo);
     }

     public Object ConvertEntityToObject(IEntity iEntity)
     {
         IDictionary<string, Object> map = this._map;
         string hashCode = iEntity.GetHashCode().ToString();
         Object resultObj = this.ResultObject;
         bool contain = map.ContainsKey(hashCode);
         if (contain)
         {// 已经序列化过了
             this.AddRefObject(resultObj, hashCode);
             return resultObj;
         }
         else
         {
             map.Add(hashCode, iEntity);
         }
         this.AddHashField(resultObj, hashCode);
         string typeName = iEntity.GetTypeName();
         this.AddTypeField(resultObj, typeName);

         IEntityInfo ei = MetadataHelper.Instance.GetEntityInfo(iEntity);
         IPropertyInfo[] properties = ei.GetAllProperties();

         Object propertyObject = null;
         foreach (IPropertyInfo pi in properties)
         {
             propertyObject = null;
             string propName = pi.Name;
             DataType dataType = pi.DataType;

             bool isNull = iEntity.IsNull(propName);
             if (isNull)
             {
                 continue;
             }

             Object propValue = iEntity[propName];
             if (propValue == null)
             {
                 continue;
             }

             // 集合类型（一对多关联）
             if (CollectionInfo.IsCollectionProperty(pi))
             {
                 if (dataType.BasicType == BasicDataType.String)
                 {
                     propertyObject = StringListPropertyToObject((StringList)propValue);
                 }
                 else if (dataType.BasicType == BasicDataType.DataDict)
                 {
                     propertyObject = DataDictPropertyToObject((DataDictList)propValue);
                 }
                 else if (dataType.BasicType == BasicDataType.GTPEnum)
                 {
                     propertyObject = GTPEnumListPropertyToObject((IGTPEnumList)propValue);
                 }
                 //处理列表类型，包括字符串列表，字典列表
             }
             else if (propValue is IList || dataType != null && dataType.IsCollection)
             {
                 propertyObject = ArrayPropertyToObject(dataType, propValue);
             }
             else if (pi.IsMultilingual)
             { // 多语言字段
                 MultilingualString i18n = (MultilingualString)propValue;// en.GetMultilingualString(propName);
                 propertyObject = MultiLanguagePropertyToObject(i18n);
             }
             else
             { // 简单的值属性, 一对一关联或多对一关联
                 propertyObject = MetadataSingleObjectPropertyToObject(propValue, dataType);
             }
             if (propertyObject != null)
             {
                 this.AddPropertyObjectToResultObject(resultObj, propName, propertyObject);
             }
         }
         return resultObj;
     }
     protected Object ArrayPropertyToObject(DataType dataType, Object propValue)
     {
         Object resultObj = this.ArrayObject;
         IList listValues = propValue as IList;//en.Get(propName) as IList;
         if (listValues != null && listValues.Count > 0)
         {
             // 序列化集合中每个子项
             foreach (Object value in listValues)
             {
                 if (value == null)
                 {
                     continue;
                 }

                 Object subObject = this.MetadataSingleObjectPropertyToObject(value, dataType);
                 this.ArrayObjectAddItem(resultObj, subObject);
             }
         }
         return resultObj;
     }

     protected Object MetadataSingleObjectPropertyToObject(Object propValue, DataType dataType)
     {
         BasicDataType bdt = dataType.BasicType;
         Object resultObj = null;
         switch (bdt)
         {
             case BasicDataType.RuntimeClass:
                 resultObj = this.PocoObjectToObject(propValue);
                 break;
             case BasicDataType.GTPEnum:
                 {
                     // Enum
                     IEnum enumValue = propValue as IEnum;
                     resultObj = GTPEnumToObject(enumValue);

                     break;
                 }
             case BasicDataType.Entity:
             case BasicDataType.Poco:
             case BasicDataType.Query:
                 resultObj = this.ConvertEntityToObject((IEntity)propValue);
                 break;
             case BasicDataType.DataDict:
                 //序列化单字典类型
                 resultObj = this.ConvertDataDictToObject(((DataDict)propValue).Key, ((DataDict)propValue).Value);
                 break;
             default:
                 resultObj = this.NativeObjectToObject(propValue);
                 break;
         }
         return resultObj;
     }

     protected Object PocoObjectToObject(Object targetObj)
     {
         Object resultObj = this.ResultObject;
         //满足实体类型选择成runtimeclass类型。
         if (targetObj is IEntity)
         {
             return this.ConvertEntityToObject((IEntity)targetObj); ;
         }
         IDictionary<string, Object> map = this._map;
         string hashCode = targetObj.GetHashCode().ToString();
         bool contain = map.ContainsKey(hashCode);
         if (contain)
         { // 已经序列化过了
             this.AddRefObject(resultObj, hashCode);
             return resultObj;
         }
         else
         {
             map.Add(hashCode, targetObj);
         }
         this.AddHashField(resultObj, hashCode);

         System.Reflection.PropertyInfo[] propertyInfos = targetObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

         Object propertyObject = null;
         foreach (System.Reflection.PropertyInfo propertyInfo in propertyInfos)
         {
             bool ignore = Attribute.IsDefined(propertyInfo, typeof(SerializerIgnoreAttribute));
             if (ignore) continue;

             //没有get和set的不进行序列化。
             //if (!propertyInfo.CanRead || !propertyInfo.CanWrite) continue;
             if (!propertyInfo.CanRead) continue;

             AliasAttribute attr = (AliasAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(AliasAttribute));

             string name = attr != null ? attr.AliasName : propertyInfo.Name;
             Object defaultValue = attr != null ? attr.DefaultValue : null;
             Object propValue = propertyInfo.GetValue(targetObj, null);
             //值为null或者等于defaultValue 不进行序列化。
             if (propValue == null || propValue.Equals(defaultValue))
             {
                 continue;
             }

             if (propValue is IList)
             {// 集合类型
                 propertyObject = this.CollectionToObject(propValue as IList);
             }
             else
             {// 非集合类型
                 propertyObject = this.ConvertToObject(propValue);
             }
             if (propertyObject != null)
             {
                 this.AddPropertyObjectToResultObject(resultObj, name, propertyObject);
             }
         }
         return resultObj;
     }
     protected Object CollectionToObject(IList iterable)
     {
         Object resultObj = this.ArrayObject;
         if (iterable != null)
         {
             foreach (Object item in iterable)
             {
                 Object itemNode = this.ConvertToObject(item);
                 this.ArrayObjectAddItem(resultObj, itemNode);
             }
         }
         return resultObj;
     }

	 
}
